package com.cyf.util;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static java.lang.String.format;

/**
 * 违章查询工具类
 */
@Component
public class IllegalQueryUtil implements InitializingBean {

    private static final String USER_FROM = "cheyifu2017"; // 商户标识
    private static final String KEY = "1234567890123456"; // 加密秘钥
    private static final String URL = "https://wap.cx580.com/illegal?user_id=%s&user_from=%s&carnumber=%s&carcode=%s&cardrive=%s&tel=%s&token=%s"; // 请求网址
    private static final String CLIENT_ID = "cheyifu2017";

    private static final String RULE_URL = "http://chaxun.cx580.com:9008/QueryAndOrderRules.aspx";

    private static final String ENCODING = "UTF-8";
    private static CloseableHttpClient HTTP_CLIENT = null;

    private static final Logger logger = LoggerFactory.getLogger(IllegalQueryUtil.class);

    /* 违章查询规则 */
    private static final Map<String, String> ILLEGAL_QUERY_RULE_MAP = new HashMap<>();

    @Autowired
    private BasicProperties basicProperties;

    @Override
    public void afterPropertiesSet() throws Exception {
        String certPath = basicProperties.getIllegalCertPath();
        logger.info("违章查询证书位置：{}", certPath);
        String password = basicProperties.getIllegalCertPwd();
        HTTP_CLIENT = HttpsUtil.getHttpClientWithCert(certPath, password);
    }

    /*  本地测试使用该段代码  */
   /* static {
        String certPath = "D:\\pmcloudhttpsvr\\pmCloudHttpSvr\\src\\main\\resources\\jssecacerts";
        logger.info("违章查询证书位置：{}", certPath);
        String password = "changeit";
        HTTP_CLIENT = HttpsUtil.getHttpClientWithCert(certPath, password);
    }*/
    /*  本地测试使用该段代码  */

    /**
     * 获取违章查询url
     *
     * @param mobile    手机号
     * @param plate     车牌号码
     * @param carcode   车架号
     * @param cardrive  发动机号
     * @param userId    用户标识
     * @return String   失败返回null
     */
    public String getUrl(String mobile, String plate, String carcode, String cardrive, String userId) {
        // http://webtest.cx580.com:10001/illegal?user_id=123456&user_from=sograndwap&carnumber=粤DMM159&carcode=270370&cardrive=1122&token=bUSNUlLO%2fOBf4WOK9GHw14c%2fddkid6%2bGGkMAUhaGqcc%3d
        // 需要签名的原始串：user_id + user_from + carnumber
        String signOrigStr = userId + USER_FROM + plate;
        String token;
        String carnumber;
        try {
            token = URLEncoder.encode(encrypt(signOrigStr, KEY), ENCODING);
            carnumber = URLEncoder.encode(plate.trim().toUpperCase(), ENCODING);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
        return format(URL, userId, USER_FROM, carnumber, carcode, cardrive, mobile, token);
    }

    private static String encrypt(String input, String key) {
        byte[] crypted = null;

        try {
            SecretKeySpec skey = new SecretKeySpec(key.getBytes(), "AES");

            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");

            cipher.init(Cipher.ENCRYPT_MODE, skey);

            crypted = cipher.doFinal(input.getBytes());
        } catch (Exception e) {
            System.out.println(e.toString());
        }

        return (new String(Base64.encodeBase64(crypted)));
    }


    private static String decrypt(String input, String key) {
        byte[] output = null;

        try {
            SecretKeySpec skey = new SecretKeySpec(key.getBytes(), "AES");

            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");

            cipher.init(Cipher.DECRYPT_MODE, skey);

            output = cipher.doFinal(Base64.decodeBase64(input));
        } catch (Exception e) {
            System.out.println(e.toString());
        }

        return (new String(output));
    }

    public Map<String, String> auth(String mobile, String carNumber, String carCode, String carDrive, String userId) {
        HashMap<String, String> result = new HashMap<>();
        result.put("auth", "fail");
        result.put("errMsg", "");
        try {
            String url = getUrl(mobile, carNumber, carCode, carDrive, userId);
            logger.info(url);
            url = HttpsUtil.getRedirectURI(url, null, HTTP_CLIENT);
            logger.info(url);
            if (null == url) {
                return result;
            }

            System.out.println(URLDecoder.decode(url, "gb2312"));
            url = URLDecoder.decode(url, "gb2312");


            String carNmber1 = getParam(url, "carNumber");
            System.out.println("carNumber: " + carNmber1);

            String carCode1 = getParam(url, "carCode");
            System.out.println("carCode: " + carCode1);

            String carDriver1 = getParam(url, "carDriver");
            System.out.println("carDrive: " + carDriver1);

            HashMap<String, String> map = new HashMap<>();

            map.put("grant_type", "password");
            map.put("username", userId);
            map.put("password", "");
            map.put("carnumber", carNumber);
            map.put("client_id", CLIENT_ID);
            map.put("client_secret", encrypt(userId + CLIENT_ID + carNumber, KEY));
            map.put("extend", "{}");

            String json = ObjectMapperUtils.getObjectMapper().writeValueAsString(map);
            logger.debug(json);

            String token = HttpsUtil.postText("https://wap.cx580.com/OAuth/Token", map, null, HTTP_CLIENT);
            logger.debug("Token: " + token);

            int authBegin = token.indexOf(":");
            int authEnd = token.indexOf(",");
            String auth = null;
            if (authBegin > 0 && authEnd > 0 && (authBegin + 2) < token.length()) {
                auth = token.substring(authBegin + 2, authEnd - 1);
                auth = "bearer " + auth;
            }
            logger.debug("auth: " + auth);

            map.clear();
            map.put("carNumber", carNmber1);
            if (null != carCode1) {
                map.put("carCode", carCode1);
            }
            if (null != carDriver1) {
                map.put("carDriver", carDriver1);
            }
            map.put("real", "false");
            logger.debug("map: " + map);
            HashMap<String, String> headers = new HashMap<>();
            headers.put("Authorization", auth);
            String queryResult = HttpsUtil.postText("https://wap.cx580.com/api/UserCar/QueryTrafficViolation/", map, headers, HTTP_CLIENT, ENCODING);
            logger.info("query:: " + queryResult);
            if (null != queryResult ) {
                if (queryResult.contains("\"status\":true")) {
                    int indexOf = queryResult.indexOf("errMessage");
                    if (indexOf > 0 && queryResult.length() > indexOf + 13) {
                        String errMessage = queryResult.substring(indexOf + 13, queryResult.indexOf(",", indexOf + 13) - 1);
                        System.out.println(errMessage);
                        if (errMessage == null || "".equals(errMessage)) {
                            result.put("auth", "success");
                        } else {
                            result.put("errMsg", errMessage);
                        }
                    }
                } else {
                    int indexOf = queryResult.indexOf("exceptionMessage");
                    if (indexOf > 0 && queryResult.length() > indexOf + 19) {
                        String errMessage = queryResult.substring(indexOf + 19, queryResult.indexOf(",", indexOf + 19) - 1);
                        System.out.println(errMessage);
                        result.put("errMsg", errMessage);
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return result;
    }

    /**
     * 从url中获取某参数的值
     * @param url   url
     * @param paramName 参数名称
     * @return String 参数值。找不到返回null
     */
    private String getParam(String url, String paramName) {
        String value = null;
        if (StringUtils.isEmpty(url) || StringUtils.isEmpty(paramName)) {
            return null;
        }
        int begin = url.indexOf(paramName);
        if (begin > 0) {
            int end = url.indexOf("&", begin);
            begin += paramName.length() + 1;
            if (end > 0) {
                value = url.substring(begin, end);
            } else {
                value = url.substring(begin);
            }
        }
        return value;
    }


    /**
     * 获取各地区违章查询规则
     * @return  List<IllegalQueryRule>
     */
    public static List<IllegalQueryRule> getIllegalQueryRules() {
        List<IllegalQueryRule> list = null;
        String rules = HttpsUtil.get(RULE_URL, null, HTTP_CLIENT);
        System.out.println(rules);
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
        try {
            list = mapper.readValue(rules, new TypeReference<List<IllegalQueryRule>>() {
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
        return list;
    }

    /**
     * 获取某城市的违章查询规则
     * @param prefix 车牌号前两位：例如：京A
     * @return String 第一位代表车架号，第二位代表发动机号，1代表需要，0代表不需要。 例如：11， 车架号和发动机号都需要。 null代表查询失败
     */
    public static String getIllegalQueryRuleOfCity(String prefix) {
        if (prefix == null || prefix.length() != 2) {
            return null;
        }
        if (ILLEGAL_QUERY_RULE_MAP.size() == 0) {
            initIllegalQueryRuleMap();
        }
        if (ILLEGAL_QUERY_RULE_MAP.size() == 0) {
            return null;
        }
        String result = ILLEGAL_QUERY_RULE_MAP.get(prefix);

        if (result == null){
            char city = prefix.charAt(0);
            result = ILLEGAL_QUERY_RULE_MAP.get(city + "");
        }
        return result;
    }

    /**
     * 初始化违章查询规则map集合
     * 详细：将各地区违章查询规则存储到map中，key-车牌号前1/2位，value-是否需要车架号和发送机号（1需要，0不需要）
     * 例如：辽H - 11、京 - 10
     */
    private static void initIllegalQueryRuleMap() {
        List<IllegalQueryRule> illegalQueryRules = getIllegalQueryRules();
        if (illegalQueryRules != null && illegalQueryRules.size() > 0) {
            for (IllegalQueryRule illegalQueryRule : illegalQueryRules) {
                List<CityRule> cityRules = illegalQueryRule.getCities();
                for (CityRule cityRule : cityRules) {
                    String carCodeLen = cityRule.getCarCodeLen() > 0 ? "1" : "0";
                    String carEngineLen = cityRule.getCarEngineLen() > 0 ? "1" : "0";
                    ILLEGAL_QUERY_RULE_MAP.put(cityRule.getCarNumberPrefix(), carCodeLen + carEngineLen);
                }
            }
        }
    }

}